/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package jxsdgenerator.engine;


import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JTextArea;

/**
 * <p>Title: Yeradis P. Barbosa Marrero</p>
 *
 * <p>Description: A XML binding Compiler </p>
 *
 * <p>Copyright: Copyright (c) 2007 Yeradis P. Barbosa Marrero</p>
 *
 * <p>Company: MyOwn</p>
 *
 * @author Yeradis P. Barbosa Marrero
 * @version 1.0
 */
public class Generator {

    private String appPath;//batch path
    private String batchName;//batch name
    private String workingDirectory;
    private String fileName;
    private String rootPackage;
    private String cmdSCOMP;
    private String cmdCLASSDEL;
    private String cmdSRCDEL;
    private String cmdFILEDEL;
    private String cmdPACK;
    private String cmdCONFIG;
    /**
     * To know if the property load is ok
     */
    private boolean propsOK = false;
    private boolean packFILES = false;

    /*----------------------------------------------------------------------------*/
    /** 
     * Method to replace strings using regexp
     * @param OldValue
     * @param NewValue
     * @param dataToChange
     * @return devuelve la cadena modificada con los nuevos valores
     */
    public static String replaceString( String OldValue, String NewValue, String dataToChange ) {
        Pattern pattern = Pattern.compile(OldValue);
        Matcher matcher = pattern.matcher(dataToChange);
        return matcher.replaceAll(NewValue);
    }

    /**
     * Method to get the java root package used for the binding compilation
     * 
     */
    public String getRootPackage() {
        return rootPackage;
    }

    /**
     * Method to set the java root package needed for the new binding compilation
     * 
     */
    public void setRootPackage( String rootPackage ) {
        this.rootPackage = rootPackage;
    }

    /**
     * Method used the get the systen file separator
     * mean Slash(/) in unix systems and BackSlash(\) on windows systems
     * and other kind of file separators used in the Host OS
     */
    public String getFileSeparator() {
        return System.getProperty("file.separator");
    }

    /**
     * Method to get the filename used for the jar generatior
     */
    public String getFileName() {
        return fileName;
    }

    /**
     * Method used to set the filename needed for the jar creation
     */
    public void setFileName( String fileName ) {
        this.fileName = replaceString(" ", "", fileName);
    }

    public boolean isPackFILES() {
        return packFILES;
    }

    public void setPackFILES( boolean packFILES ) {
        this.packFILES = packFILES;
    }

    
    /**
     * Method used the clean the whitespaces on the workingdirectory text
     */
    public String trimWorkingDirectory() {
        return replaceString(" ", "", workingDirectory);
    }

    /**
     * Method used to get the directory used for the localization of Schemas
     */
    public String getWorkingDirectory() {
        return workingDirectory;
    }

    /**
     * Set the working directory necessary for building the xml binding
     * @param workingDirectory
     */
    public void setWorkingDirectory( String workingDirectory ) {
        String temppath = "";
        if ( !this.getFileSeparator().equalsIgnoreCase("/") ) {
            //then is windows (thats what i hope :P)
            temppath = replace(workingDirectory, "\\", "\\\\");
            System.out.println("New formatted path: " + temppath);
        }
        this.workingDirectory = temppath;
    }

    /**
     * Method used to build the needed schema config for the binding compilation
     */
    private void buildXSDConfig( String file ) {
        FileOutputStream out; // declare a file output object
        PrintStream p; // declare a print stream object
        try {
            // Create a new file output stream
            out = new FileOutputStream(getWorkingDirectory() + getFileSeparator() + "config.xsdconfig");
            // Connect print stream to the output stream
            p = new PrintStream(out);
            
            //cmd = replaceString("\\$xsd2PROCESS\\$", fileList[i], cmd);
            String txtConfig = replaceString("\\$xsd2PROCESS\\$",replaceString(".xsd", "", file), cmdCONFIG);
            System.out.println("Creating config file: "+txtConfig);
            p.println(txtConfig);
            //p.println("<xb:config xmlns:pol=\"http://www.tesipro.com\" xmlns:xb=\"http://www.bea.com/2002/09/xbean/config\"><xb:namespace uri=\"##any\"><xb:package>" + getRootPackage() + "." + replaceString(".xsd", "", file) + "</xb:package></xb:namespace></xb:config>");
            p.close();
        }
        catch (Exception e) {
            System.err.println("Error writing to file");
        }

    }

    /**
     * Metodo chapucero para reemplazar los jodios slashes y backslashes
     * ya que con las expresiones regulares, ufff aun no he podido saltarme esa barrerilla
     * @param source
     * @param pattern
     * @param replace
     * @return
     */
    public static String replace( String source, String pattern, String replace ) {
        if ( source != null ) {
            final int len = pattern.length();
            StringBuffer sb = new StringBuffer();
            int found = -1;
            int start = 0;

            while ((found = source.indexOf(pattern, start)) != -1) {
                sb.append(source.substring(start, found));
                sb.append(replace);
                start = found + len;
            }

            sb.append(source.substring(start));

            return sb.toString();
        } else {
            return "";
        }
    }

    /**
     * Constructor of the Engine Generator
     * @param txtWorkingDirectory
     * @param txtRootpackage
     * @param txtFilename
     */
    public Generator( String txtWorkingDirectory, String txtRootpackage, String txtFilename ) {
        this.setWorkingDirectory(txtWorkingDirectory);
        this.setRootPackage(txtRootpackage);
        this.setFileName(txtFilename);
        loadProperties();
        prepareProperties();
    }

    private void loadProperties() {
        try {
            /*Aqui almaceno la ruta desde donde se esta ejecutando la aplicacion, pero solo la ruta*/
            appPath = System.getProperty("user.dir") + System.getProperty("file.separator");

            Properties props = new Properties();
            System.out.println("Loading properties file.... (config.properties)");
            props.load(new FileInputStream("config.properties"));
            cmdSCOMP = props.getProperty("cmdSCOMP");
            System.out.println("Loaded cmdSCOMP property= " + cmdSCOMP);
            cmdCLASSDEL = props.getProperty("cmdCLASSDEL");
            System.out.println("Loaded cmdCLASSDEL= " + cmdCLASSDEL);
            cmdSRCDEL = props.getProperty("cmdSRCDEL");
            System.out.println("Loaded cmdSRCDEL= " + cmdSRCDEL);
            cmdFILEDEL = props.getProperty("cmdFILEDEL");
            System.out.println("Loaded cmdFILEDEL= " + cmdFILEDEL);
            cmdPACK = props.getProperty("cmdPACK");
            System.out.println("Loaded cmdPACK= " + cmdPACK);
            cmdCONFIG = props.getProperty("cmdCONFIG");
            System.out.println("Loaded cmdCONFIG= "+cmdCONFIG);
            propsOK = true;
        }
        catch (IOException ex) {
            propsOK = false;
            System.out.println("Properties load  error: " + ex.getMessage());
        }

    }

    private void prepareProperties() {

        cmdSCOMP = replaceString("\\$workingDIR\\$.", this.getWorkingDirectory() + this.getFileSeparator() + this.getFileSeparator(), cmdSCOMP);
        cmdCLASSDEL = replaceString("\\$workingDIR\\$.", this.getWorkingDirectory(), cmdCLASSDEL);
        cmdSRCDEL = replaceString("\\$workingDIR\\$.", this.getWorkingDirectory(), cmdSRCDEL);
        cmdFILEDEL = replaceString("\\$workingDIR\\$.", this.getWorkingDirectory(), cmdFILEDEL);
        cmdPACK = replaceString("\\$workingDIR\\$.", this.getWorkingDirectory() + this.getFileSeparator() + this.getFileSeparator(), cmdPACK);
        cmdCONFIG=replaceString("\\$rootPackage\\$",this.getRootPackage(),cmdCONFIG);        
        System.out.println("parsed cmdSCOMP= " + cmdSCOMP);
        System.out.println("parsed cmdCLASSDEL= " + cmdCLASSDEL);
        System.out.println("parsed cmdSRCDEL= " + cmdSRCDEL);
        System.out.println("parsed cmdFILEDEL= " + cmdFILEDEL);
        System.out.println("parsed cmdPACK=" + cmdPACK);
        System.out.println("parsed cmdCONFIG="+cmdCONFIG);
    }

    /**
     * Method to run an external command
     * 
     */
    private void execCMD( String cmd ) throws IOException {
        Runtime run = Runtime.getRuntime();
        Process process = run.exec(cmd);
        InputStream is = process.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line + "\n");
        }

    }

    private void cleanCLASS() throws Exception {
        //String rdclass = "cmd.exe /c rd " + quotedSTR(getWorkingDirectory() + getFileSeparator() + "javaclass") + " /s/q ";
        System.out.println("Comenzando proceso de borrado de archivos temporales de classes\n");
        execCMD(cmdCLASSDEL);

    }

    private void cleanSRC() throws Exception {
        //String rdsrc = "cmd.exe /c rd " + quotedSTR(getWorkingDirectory() + getFileSeparator() + "javasrc") + " /s/q ";
        System.out.println("Comenzando proceso de borrado de archivos temporales de src\n");
        execCMD(cmdSRCDEL);

    }

    private void cleanCONFIG() throws Exception {
        //String delconfig = "cmd.exe /c del " + quotedSTR(getWorkingDirectory() + getFileSeparator() + "config.xsdconfig");
        System.out.println("Comenzando proceso de borrado de archivos temporales de configuracion del xsd\n");
        execCMD(cmdFILEDEL);

    }

    /**
     * Method used to clean all unnecesary files and folders
     */
    private void cleanGarbage() {
        try {
            this.cleanCLASS();
            this.cleanSRC();
            this.cleanCONFIG();

        }
        catch (Exception ex) {
            System.err.println("Ocurrio la siguiente excepcion mientras se intentaba eliminar los archivos temporales. Error: " + ex.getMessage());
        }
    }

    /**
     * Method used to package the compilation
     */
    private void buildJar() {
        try {

            cmdPACK = replaceString("\\$packNAME\\$", this.getFileName(), cmdPACK);
            //String cmd = "jar cvfM " + quotedSTR(getWorkingDirectory() + getFileSeparator() + getFileName() + ".jar") + " -C " + quotedSTR(getWorkingDirectory() + getFileSeparator() + "javaclass") + " .";
            String cmd = cmdPACK;
            System.out.println(cmd);
            execCMD(cmd);
        }
        catch (IOException ex) {
            System.err.println("Jar Build error: " + ex.getMessage());
        }
    }

    /** 
     * Method to get the file content of a directory
     * 
     */
    private String[] getContentDir() {
        String[] list = new File(getWorkingDirectory() + getFileSeparator()).list();
        return list;
    }

    private boolean checkPath() {
        File path = new File(this.getWorkingDirectory());
        return path.isDirectory();
    }

    /**
     * Method to doble quote strings
     */
    private String quotedSTR( String str ) {
        return "\"" + str + "\"";
    }

    /**
     * Main method of the class , used for the xml binding compilation
     * Package Builder , only for windows at the moment
     * this method redirect consule to JTextArea
     */
    public void Build() {
        try {
            if ( !propsOK ) {
                throw new Exception("Properties are missing....\nPlease check if config.properties is accesible and try again.");
            }
            if ( !checkPath() ) {
                throw new Exception("The path \" " + getWorkingDirectory() + " \" does not exist or its not correct. \nCheck if its a correct path for the schema files.");
            }
//            cleanGarbage();
            String[] fileList = getContentDir();
            int len = (fileList == null ? 0 : fileList.length);
            int xsdcount = 0;
            String temp;
            for (int i = 0; i < len; i++) {
                if ( fileList[i].indexOf(".xsd") >= 0 ) {
                    temp = fileList[i];
                    System.err.println("Schema to processs : " + fileList[i]);
                    buildXSDConfig(fileList[i]);
//                    String cmd = "cmd.exe /c scomp.cmd -d " + quotedSTR(getWorkingDirectory() + getFileSeparator() + "javaclass") + " -src " + quotedSTR(getWorkingDirectory() + getFileSeparator() + "javasrc") + " -ms 64m -mx 256m -javasource 1.4 " + quotedSTR(getWorkingDirectory() + getFileSeparator() + fileList[i]) + " " + quotedSTR(getWorkingDirectory() + getFileSeparator() + "config.xsdconfig");
                    String cmd = cmdSCOMP;
                    cmd = replaceString("\\$xsd2PROCESS\\$", fileList[i], cmd);
                    System.out.println(cmd);
                    execCMD(cmd);
                    cmd = "";
                    xsdcount++;
                }
            }
            System.out.println(xsdcount + " schema files processed from " + len);

            if ( packFILES ) {
                buildJar();
            }
//            cleanGarbage();
        }
        catch (Exception e) {
            Logger.getLogger(Generator.class.getName()).log(Level.SEVERE, null, e);
        }
    }

    
    



;
    }


